package com.hilatest.wsexample.basictest.chapter1;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Iterator;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;

import org.junit.Test;

public class SOAPDemo {

	private static final String LocalName="TimeRequest";
	private static final String NameSpace="http://chapter1.basic.wsexample.hilatest.com/";
	private static final String NamespacePrefix="ms";
	
	private ByteArrayInputStream in;
	private ByteArrayOutputStream out;
	
	@Test
	public void request() throws SOAPException, IOException{
		
		// build a soap message to send to an output stream
		SOAPMessage msg = createSOAPMessage();
		
		/*
		 * Inject the appropriate information into the message
		 * In this case,only the (optional) message header is used
		 * and the body is empty
		 */
		SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
		SOAPHeader   hdr = env.getHeader();
		
		//Add an element to the SOAP header
		Name loopup_name = creatQname(msg);
		hdr.addHeaderElement(loopup_name).addTextNode("time_request");
		
		/*
		 * Simulate sending the SOAP message to a remote system by writing it to a ByteArrayOutputStream
		 */
		out  = new ByteArrayOutputStream();
		msg.writeTo(out);
		
		this.trace("the send SOAP Message:",msg);
		
		SOAPMessage response = processRequest();
		extractContentsAndPrint(response);
		
	}

	public void extractContentsAndPrint(SOAPMessage msg) throws SOAPException {
		SOAPBody body =  msg.getSOAPBody();
		
		Name lookupName = this.creatQname(msg);
		@SuppressWarnings("unchecked")
		Iterator<Node>     it  = body.getChildElements(lookupName);
		Node next = it.next();
		String value = (next==null)?"Error!":next.getValue();
		System.out.println("\n\n returned from server"+value);
		
	}

	public SOAPMessage processRequest() throws SOAPException, IOException {
        processIncomingSOAP();
        this.coordinateStreams();
		return this.createSOAPMessage(in);
	}

	public void processIncomingSOAP() throws SOAPException, IOException {
		/*
		 * Copy output stream to input stream to Simulate
		 * coordinated stream over a network connection
		 */
		coordinateStreams();
		
		/*
		 * create the ".received" SOAP message from
		 * the input stream
		 */
		SOAPMessage msg = this.createSOAPMessage(in);
		
		/*
		 * Inspect the SAP header for the keyword 'time_request'
		 * and process the request if the keyword occurs
		 */
		Name lookupName = this.creatQname(msg);
		
		SOAPHeader   hdr = msg.getSOAPHeader();
		
		@SuppressWarnings("unchecked")
		Iterator<Node>     it  = hdr.getChildElements(lookupName);
		Node next = it.next();
		String value = (next==null)?"Error!":next.getValue();
		
		//if SOAP Message contains request fro the time,create a 
		//new SOAP message with the current time in the body
		if(value.toLowerCase().contains("time_request")){
			//Extract the body and add the current time as an element
			
			String now = new Date().toString();
			SOAPBody body = msg.getSOAPBody();
			body.addBodyElement(lookupName).addTextNode(now);
			msg.saveChanges();
			
			msg.writeTo(out);
			
			this.trace("The reveived/processd SOAP message", msg);
		}
		
	}

	public void coordinateStreams() {
		in = new ByteArrayInputStream(out.toByteArray());
		out.reset();
		
	
	}

	public void trace(String string, SOAPMessage msg) {
		System.out.print("\n");
		System.out.print(string);
		
			try {
				msg.writeTo(System.out);
			} catch (SOAPException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		
	}

	public Name creatQname(SOAPMessage msg) {
		Name result = null;
		try {
			SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
			result             = env.createName(LocalName, NamespacePrefix,NameSpace);
		} catch (SOAPException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return result;
	}

	private SOAPMessage createSOAPMessage() {
		
		SOAPMessage result = null;
		
		try {
			MessageFactory mf =MessageFactory.newInstance();
			result               =mf.createMessage();
		} catch (SOAPException e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	public SOAPMessage createSOAPMessage(InputStream in) {
		
		SOAPMessage result = null;
		
		try {
			MessageFactory mf =MessageFactory.newInstance();
			result               =mf.createMessage(null, //ignore MIME headers
					                               in);  // stream source
		} catch (SOAPException e) {
	
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return result;
	}
}
